from pyjvm.instructions.common import Index16Instruction, Instruction, BytecodeReader, Index8Instruction
from pyjvm.runtime.thread import Frame

from pyjvm.runtime.metadata import ClassRef
from pyjvm.runtime.strpool import StringPool


class ACONST_NULL(Instruction):
    """
    将null引用推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(None)


class DCONST_0(Instruction):
    """
    将double数字0推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(0.0)


class DCONST_1(Instruction):
    """
    将double数字1推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(1.0)


class FCONST_0(Instruction):
    """
    将float数字0推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(0.0)


class FCONST_1(Instruction):
    """
    将float数字1推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(1.0)


class FCONST_2(Instruction):
    """
    将float数字2推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(2.0)


class ICONST_M1(Instruction):
    """
    将int数字-1推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(-1)


class ICONST_0(Instruction):
    """
    将int数字0推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(0)


class ICONST_1(Instruction):
    """
    将int数字1推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(1)


class ICONST_2(Instruction):
    """
    将int数字2推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(2)


class ICONST_3(Instruction):
    """
    将int数字3推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(3)


class ICONST_4(Instruction):
    """
    将int数字4推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(4)


class ICONST_5(Instruction):
    """
    将int数字5推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(5)


class LCONST_0(Instruction):
    """
    将long数字0推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(0)


class LCONST_1(Instruction):
    """
    将long数字1推入操作数栈顶
    """

    def execute(self, frame: Frame):
        frame.operand_stack.push(1)


class BIPUSH(Instruction):
    """
    push byte
    从操作数栈获取一个byte类型整数，推入栈顶
    """

    def __init__(self):
        Instruction.__init__(self)
        self.val = None

    def fetch_operands(self, reader: BytecodeReader):
        self.val = reader.int8()

    def execute(self, frame: Frame):
        frame.operand_stack.push(self.val)


class SIPUSH(Instruction):
    """
    push short
    从操作数栈获取一个short类型整数，推入栈顶
    """

    def __init__(self):
        Instruction.__init__(self)
        self.val = None

    def fetch_operands(self, reader: BytecodeReader):
        self.val = reader.int16()

    def execute(self, frame: Frame):
        frame.operand_stack.push(self.val)


class UnsurportedLDC(Exception):
    pass


def ldc(frame: Frame, index: int):
    stack = frame.operand_stack
    klass = frame.method.klass
    const_pool = klass.runtime_const_pool
    val = const_pool[index]
    if val is None or isinstance(val, int) or isinstance(val, float):
        stack.push(val)
    elif isinstance(val, ClassRef):
        j_class = val.resolved_class().j_class
        stack.push(j_class)
    elif isinstance(val, str):
        j_str = StringPool.new(klass.loader, val)
        stack.push(j_str)
    else:
        print('idc todo: ', val)
        raise UnsurportedLDC("不支持的ldc类型：%s" % val)


class LDC(Index8Instruction):

    def execute(self, frame: Frame):
        ldc(frame, self.index)


class LDC_W(Index16Instruction):

    def execute(self, frame: Frame):
        ldc(frame, self.index)


class LDC2_W(LDC_W):
    pass


__all__ = ['ACONST_NULL', 'BIPUSH', 'DCONST_0', 'DCONST_1', 'FCONST_0', 'FCONST_1', 'FCONST_2',
           'ICONST_0', 'ICONST_1', 'ICONST_2', 'ICONST_3', 'ICONST_4', 'ICONST_5', 'ICONST_M1',
           'LDC', 'LCONST_0', 'LCONST_1', 'LDC2_W', 'LDC_W', 'SIPUSH']
